<template>
  <el-table-column :class-name="`editable-column${editable ? ' is-editable' : ''}`" v-bind="$attrs">
    <template #default="data">
      <div class="editable-column--content"
           tabindex="0"
           @click="onCellClick(data.row)"
           @keydown="onCellKeydown(data.row, $event)"
           @focus="onCellFocus(data.row)"
      >
        <span class="editable-column--mark" v-if="editable"></span>
        <cell-editor :field="fieldName"
                     :editor-type="editorType"
                     :editor-items="editorItems"
                     :editor-validator="editorValidator"
                     ref="editor"
                     @blur="onCellBlur(data.row)"
                     :row="data.row" v-if="editorStore.isCellEditing(data.row, fieldName)"/>
        <span v-else>
          <slot v-bind="data" :value="editorStore.getCellValue(data.row, fieldName)">
            {{
              renderer ? renderer({
                row: data.row, field: fieldName, value: editorStore.getCellValue(data.row, fieldName)
              }) : editorStore.getCellValue(data.row, fieldName)
            }}
          </slot>
          <span class="editable-column--changed-mark" v-if="editorStore.isCellChanged(data.row, fieldName)"></span>
        </span>
      </div>
    </template>
  </el-table-column>
</template>

<script>
import CellEditor from './CellEditor'

export default {
  components: {CellEditor},
  inheritAttrs: false,
  name: 'EditableColumn',
  props: {
    editable: {
      type: Boolean,
      default: false
    },
    editorType: {
      type: String,
      default: 'text',
      validator(v) {
        return ['text', 'textarea', 'select', 'checkbox', 'radio'].indexOf(v) !== -1
      }
    },
    editorItems: {
      type: Array
    },
    editorTrigger: {
      type: String,
      default: 'focus',
      validator(v) {
        return ['click', 'manual', 'focus'].indexOf(v) !== -1
      }
    },
    editorValidator: {
      type: Function
    },
    renderer: {
      type: Function
    }
  },
  inject: ['editorStore'],
  computed: {
    fieldName() {
      return this.$attrs.prop
    }
  },
  methods: {
    onCellClick(row) {
      if (this.editorTrigger !== 'editorTrigger') {
        return
      }
      if (!this.editable) {
        return
      }
      this.$nextTick(() => {
        this.editorStore.beginEditCell(row, this.fieldName)
      })
    },
    onCellFocus(row) {
      if (this.editorTrigger !== 'focus') {
        return
      }
      if (!this.editable) {
        return
      }
      this.$nextTick(() => {
        this.editorStore.beginEditCell(row, this.fieldName)
      })
    },
    onCellKeydown(row, e) {
      const {keyCode} = e
      switch (keyCode) {
        case 9:
          // Tab 进入编辑
          // this.editorStore.beginEditCell(row, this.fieldName)
          break
        case 27:
          // ESC 取消编辑
          this.editorStore.cancelEditCell(row, this.fieldName)
          break
      }
    },
    onCellBlur(row) {
      if (!this.$refs.editor.commitValue()) {
        return
      }
      this.$nextTick(() => {
        this.editorStore.endEditCell(row, this.fieldName)
      })
    }
  }
}
</script>

<style lang="less" scoped>
.editable-column--content {
  width: 100%;
  height: 100%;
  outline: none;
}

.editable-column--changed-mark {
  position: absolute;
  top: 0;
  left: 0;
  border-width: 4px;
  border-color: rgba(236, 170, 47, 0.8) transparent transparent rgba(236, 170, 47, 0.8);
  border-style: solid;
}

.editable-column--mark {
  position: absolute;
  top: 0;
  left: 0;
  border-width: 4px;
  border-color: rgba(47, 201, 236, 0.8) transparent transparent rgba(47, 201, 236, 0.8);
  border-style: solid;
  display: none;
}
</style>
<style lang="less">
.el-table__cell.editable-column {
  position: relative;

  &.is-editable {
    cursor: default;

    &:hover {
      .editable-column--mark {
        display: block;
      }
    }
  }
}
</style>
